

// generate-vue-template.js
const fs = require('fs').promises;
const fsm = require('fs');
const path = require('path');

async function gListIndexTemplate({
    modelLabel,
    fields,        // 表字段数组 如: ['id', 'name', 'age']
    searchFields,
    apiPath,
    exportApi,
    fileName = 'ListTable',
    outputDir = './src/components',
    modelName
}) {
    const addEditFileName = toUpperCamelCase(modelName) + 'AddEdit';
    const detailFileName = toUpperCamelCase(modelName) + 'Detail';
    const searchTemplate = searchFields.map(field => {
        if (field.type === 'select') {
            return `
             <el-form-item label="${field.fieldLabel}">
                <el-select
                        v-model="queryParams.${field.fieldName}"
                        style="width: 188px"
                        placeholder="请选择${field.fieldLabel}"
                        multiple
                        clearable
                        @change="handleQuery"
                >
                ${field.selectOpt.map(opt => `<el-option label="${opt.label}" value="${opt.value}" />`).join('\n          ')}
                </el-select>
            </el-form-item>`
        }
        if (field.type === 'input') {
            return `
                <el-form-item label="${field.fieldLabel}">
                    <el-input
                        v-model="queryParams.${field.fieldName}"
                        placeholder="请输入${field.fieldLabel}"
                        clearable
                        style="width: 160px"
                        @input="handleQuery"
                />
                </el-form-item>`
        }
    }).join('\n          ')

    const template = `<template>
    <PageLayout>
        <!-- 表格布局 -->
        <TableContainer height="calc(100vh - 100px)">
            <TableLayout ref="tableLayout" :loader="getList" tableRowKey="id" @reset="reset">
                <!-- 头部搜索 -->
                <template #header>
                    <el-form ref="queryRef" :inline="true" :model="queryParams" label-width="75px" class="header-form">
                    ${searchTemplate}
                    </el-form>
                </template>

                <!-- 操作栏--左 -->
                <template #operator-left>
                    <el-button type="warning" plain @click="handleExport">导 出</el-button>
                    <el-button type="primary" plain @click="handleAdd">新 增</el-button>
                </template>

                <!-- 操作栏-右 -->
                <template #operator-right>
                    <TableOperatorSort
                        :list="sortableHeader"
                        isDrag
                        paramKey="value"
                        @column-change="handleColumnChange"
                        @drag-end="handleDragEnd"
                    ></TableOperatorSort>
                </template>
                <!-- 列表 -->
                <template #columns>
                    <TableColumn label="序号" type="order" width="55"></TableColumn>
                    <template v-for="(column, i) in tableHeader" :key="column.value + i">
                        <TableColumn
                            :label="column.label"
                            :prop="column.value"
                            :width="column.width"
                            :fixed="column.fixed"
                            min-width="120"
                            showOverflowTooltip
                        >
                            <template v-if="column.key == 'name'" #default="{ row }">
                                <span class="link-title" @click="handlePreview(row)">
                                    {{ row.name }}
                                </span>
                            </template>
                            <template v-else-if="column.key == 'subjectType'" #default="{ row }">
                                <span v-if="row.subjectType == 1">收入</span>
                                <span v-else-if="row.subjectType == 2">外包费用</span>
                                <span v-else-if="row.subjectType == 3">期间费用</span>
                                <span v-else>--</span>
                            </template>
                        </TableColumn>
                    </template>
                    <TableColumn fixed="right" label="操作" width="160">
                        <template #default="{ row }">
                            <TableAction>
                                <TableActionItem @click="handleUpdate(row)">编辑</TableActionItem>
                                <TableActionItem type="danger" @click="handleDelete(row)">删除</TableActionItem>
                            </TableAction>
                        </template>
                    </TableColumn>
                </template>
            </TableLayout>
        </TableContainer>

        <!-- 新增和编辑 -->
        <${addEditFileName} ref="addEditRef" @refresh="handleQuery" />

        <!-- 详情 -->
        <${detailFileName} ref="detailRef" />
    </PageLayout>
</template>

<script setup name="${modelName}">
import { getInstanceList, deleteInstance } from '${apiPath}';
import { reactive } from 'vue';
import ${addEditFileName} from './components/${addEditFileName}.vue';
import ${detailFileName} from './components/${detailFileName}.vue';
import columnConfig from './column';
import { useColumns } from '@opro/vhook';
import { getTableConfig, updateTableConfig } from '@/api/table/table';

const { proxy } = getCurrentInstance();
const columnRef = ref(columnConfig);
const columnSort = ref([]);
const addEditRef = ref();

const { tableHeader, sortableHeader, handleColumnChange, handleDragEnd } = useColumns(
    '${modelName}_${Date.now()}',
    columnConfig,
    'value',
    proxy,
    getTableConfig,
    updateTableConfig,
);

onBeforeMount(() => {
    columnSort.value = JSON.parse(JSON.stringify(columnRef.value));
});

const queryParams = reactive({
    ${searchFields.map(field => `${field.fieldName}: null,`).join('\n          ')}
    page: 1,
    pageSize: 20,
});

const tableLayout = ref();

function handleQuery() {
    queryParams.page = 1;
    tableLayout.value.refresh();
}

function reset() {
    ${searchFields.map(field => `queryParams.${field.fieldName} = null;`).join('\n          ')}
    queryParams.page = 1;
    queryParams.pageSize = 20;
    tableLayout.value.refresh();
}

async function getList(params) {
    const res = await getInstanceList({ ...queryParams, ...params });
    return { records: res.rows || [], total: res.total || 0 };
}

function handleExport() {
      proxy.download('${exportApi}', {
    ...queryParams.value
  }, '${modelLabel}_${new Date().getTime()}.xlsx')
}

function handleAdd() {
    addEditRef.value?.open();
}

function handleUpdate(row) {
    addEditRef.value?.open(row);
}

const detailRef = ref(null);

function handlePreview(row) {
    detailRef.value?.open(row);
}

async function handleDelete(row) {
    await proxy.$modal.confirm('确定删除？');
    const result = await deleteInstance(row.id);
    if (result.code === 200) {
        proxy.$modal.msgSuccess('删除成功');
        tableLayout.value.refresh();
    } else {
        proxy.modal.msgError(result.msg);
    }
}

function getTableData() {
    handleQuery();
}
</script>
<style lang="scss" scoped>
.header-form {
    .el-form-item {
        margin-bottom: 0;
    }
}
.link-title {
    color: #409eff;
    cursor: pointer;
    user-select: none;
}

.link-title:hover {
    color: #66b1ff;
}

</style>
`;

    try {
        fsm.mkdirSync(outputDir, { recursive: true });
    } catch (err) {
        console.error('创建目录失败:', err);
    }

    // 写入文件
    const outputPath = path.join(outputDir, `${fileName}.vue`);
    await fs.writeFile(outputPath, template.trim());
    console.log(`Vue模板已生成至: ${outputPath}`);
}

async function gColumnTemplate({
    fields,        // 表字段数组 如: ['id', 'name', 'age']
    searchFields,
    apiPath,
    fileName = 'ListTable',
    outputDir = './src/components'
}) {

    const template = `export default [
        ${fields.map(field => `{
            value: '${field.fieldName}',
            label: '${field.fieldLabel}',
            checked: ${field.checked},
            ${field.width ? `width:  ${field.width},` : ''}
        },`).join('\n          ')}
    ];
    `;

    // 写入文件
    const outputPath = path.join(outputDir, `${fileName}.js`);
    await fs.writeFile(outputPath, template.trim());
    console.log(`column模板已生成至: ${outputPath}`);
}

async function gAddEditTemplate({
    modelLabel,
    formFields,
    fileName,
    outputDir
}) {
    const itemTemplate = formFields.map(field => {
        return `<el-col :span="24">
            <el-form-item
                label="${field.fieldLabel}"
                prop="${field.fieldName}"
                :rules="[{ required: true, message: '请输入${field.fieldLabel}', trigger: 'blur' }]"
            >
                <el-input
                    v-model="form.${field.fieldName}"
                    style="width: 100%"
                    placeholder="请输入"
                />
            </el-form-item>
        </el-col>
        `
    }).join('\n          ');

    const template = `
    <template>
        <ElDialog
            v-model.sync="dialogVisible"
            :class="{ animated: true, fadeOutDown: !dialogVisible, fadeInDown: dialogVisible }"
            width="640px"
            :title="title"
            :closeOnClickModal="false"
            :modalAppendToBody="false"
            @open="openInit"
            @close="close"
            draggable
        >
            <el-form
                ref="formRef"
                :model="form"
                v-loading="loading"
                labelWidth="120px"
                labelPosition="right"
                labelSuffix=":"
            >
                <el-row :gutter="20">
                    ${itemTemplate}
                </el-row>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <ElButton type="primary" @click="submitPartForm">确 定</ElButton>
                    <ElButton @click="handleCancel">取 消</ElButton>
                </div>
            </template>
        </ElDialog>
    </template>

    <script setup name="${fileName}">
    import { addInstance, editInstance } from '../service';

    const { proxy } = getCurrentInstance();
    const emit = defineEmits(['refresh']);

    const formRef = ref(null);
    const form = reactive({
        id: null,
        ${formFields.map(field => {
        return `${field.fieldName}: null,  // ${field.fieldLabel}`;
    }).join('\n          ')
        }
    });

    const rowId = ref(null);
    const isAdd = ref(true);
    const isEdit = ref(false);
    const title = computed(() => (isAdd.value ? '新增${modelLabel}' : '编辑${modelLabel}'));
    const dialogVisible = ref(false);
    const loading = ref(false);

    function resetForm() {
        formRef.value?.resetFields();
    }

    function handleCancel() {
        dialogVisible.value = false;
        resetForm();
    }

    function close() {
        dialogVisible.value = false;
        resetForm();
    }

    function submitPartForm() {
        formRef.value?.validate(valid => {
            if (valid) {
                // 验证通过，提交表单
                if (isAdd.value) addSubmit();
                if (isEdit.value) editSubmit();
            } else {
                // 验证不通过，提示错误信息
                console.log('error submit!!');
                return false;
            }
        });
    }

    function addSubmit(params) {
        form.id = null;
        addInstance(form).then(res => {
            if (res.code === 200) {
                proxy.$modal.msgSuccess('操作成功');
                close();
                emit('refresh');
            }
        });
    }

    function editSubmit(params) {
        editInstance(form).then(res => {
            if (res.code === 200) {
                proxy.$modal.msgSuccess('操作成功');
                close();
                emit('refresh');
            }
        });
    }

    // 需要延迟获取一些信息时使用，如异步获取备选下拉选项
    function openInit(params) {
       // if (isEdit.value) {
          
       // } else {
          
       // }
    }

    const open = row => {
        isAdd.value = !row;
        isEdit.value = !!row;
        dialogVisible.value = true;
        if (isEdit.value) {
            rowId.value = row.id;
            form.id = row.id;
            ${formFields.map(field => {
            return `form.${field.fieldName} = row.${field.fieldName} `;
        }).join('\n          ')
        }
        }
    };

    defineExpose({
        open,
    });
    </script>

    <style lang="scss" scoped>
    .title {
        line-height: 24px;
        font-weight: bold;
        border-bottom: 1px solid #ddd;
        padding-top: 10px;
        margin-bottom: 10px;
    }

    ::v-deep(.el-descriptions__label) {
        width: 110px;
    }

    ::v-deep(.detail-img #upload) {
        display: none;
    }

    .form-layout {
        margin-top: 20px;
    }

    .form-title {
        margin-left: 4px;
        font-size: 16px;
        padding-bottom: 14px;
    }
    .section-title {
        margin-left: 4px;
        font-size: 16px;
        padding-bottom: 14px;
        border-bottom: 1px solid #ddd;
        margin-bottom: 20px;
        padding-left: 4px;
        position: relative;
    }
    .section-title::after {
        content: '';
        position: absolute;
        width: 6px;
        height: 20px;
        background-color: #409eff;
        left: -10px;
        top: 2px;
    }
    .add-btn {
        padding-bottom: 14px;
    }
    </style>
    `;

    try {
        fsm.mkdirSync(outputDir + '/components/', { recursive: true });
    } catch (err) {
        console.error('创建目录失败:', err);
    }

    // 写入文件
    const outputPath = path.join(outputDir + '/components/', `${fileName}.vue`);
    await fs.writeFile(outputPath, template.trim());
    console.log(`新增编辑弹框模板已生成至: ${outputPath}`);
}

async function gDetailTemplate({
    formFields,
    fileName,
    outputDir
}) {

    const itemTemplate = formFields.map(field => {
        return `
            <el-descriptions-item label="${field.fieldLabel}" :span="2">
                {{ detail.${field.fieldName} }}
            </el-descriptions-item>`
    }).join('\n          ');

    const template = `
        <template>
            <el-dialog
                title="任务详情"
                v-model="dialogVisible"
                width="1200"
                :close-on-click-modal="false"
                append-to-body
                @close="close"
                @open="openInit"
            >
                <div v-loading="detailLoading">
                    <el-descriptions border :column="6">
                        ${itemTemplate}
                    </el-descriptions>
                </div>
            </el-dialog>
        </template>

        <script setup name="${fileName}">
        import { getInstanceDetail } from "../service";

        const detail = ref({});
        const originRow = ref({});
        const useApi = ref(false);
        const dialogVisible = ref(false);
        // 关闭
        function close() {
            dialogVisible.value = false;
        }

        const detailLoading = ref(false);
        async function infoById(detailId) {
            detailLoading.value = true;
            const result = await getInstanceDetail(detailId)
                .then((res) => res.data)
                .finally(() => {
                detailLoading.value = false;
                });
            detail.value = result;
        }

        function openInit() {
            if (useApi && originRow.value.id) {
                infoById(originRow.value.id);
            } else {
                detail.value = originRow.value;
            }
        }
        // 打开
        function open(row, api = false) {
            useApi.value = api;
            originRow.value = row;
            dialogVisible.value = true;
        }

        defineExpose({
            open,
        });
        </script>

        <style lang="scss" scoped>
        ::v-deep(.el-descriptions__label) {
            width: 100px;
            color: #909399 !important;
        }

        ::v-deep(.el-descriptions__content) {
            width: 300px !important;
            box-sizing: border-box;
        }
        </style>
    `;

    try {
        fsm.mkdirSync(outputDir + '/components/', { recursive: true });
    } catch (err) {
        console.error('创建目录失败:', err);
    }

    // 写入文件
    const outputPath = path.join(outputDir + '/components/', `${fileName}.vue`);
    await fs.writeFile(outputPath, template.trim());
    console.log(`详情弹框模板已生成至: ${outputPath}`);
}

async function gServiceTemplate({
    listApi,
    detailApi,
    delApi,
    addApi,
    editApi,
    fileName,
    outputDir
}) {

    const template = `
        import request from '@/utils/request'

        // 列表
        export function getInstanceList(params) {
            return request({
                url: '${listApi}',
                method: 'get',
                params
            })
        }

        // 详情
        export function getInstanceDetail(id) {
            return request({
                url: '${detailApi}/' + id,
                method: 'get',
            })
        }

        // 新增
        export function addInstance(data) {
            return request({
                url: '${addApi}',
                method: 'post',
                data
            })
        }

        // 编辑
        export function editInstance(data) {
            return request({
                url: '${editApi}',
                method: 'put',
                data
            })
        }

        // 删除
        export function deleteInstance(ids) {
            return request({
                url: '${delApi}/' + ids,
                method: 'delete',
            })
        }
    `;

    // 写入文件
    const outputPath = path.join(outputDir, `${fileName}.js`);
    await fs.writeFile(outputPath, template.trim());
    console.log(`service模板已生成至: ${outputPath}`);
}


function toUpperCamelCase(str) {
    return str.replace(/-([a-z])/g, function (match) {
        return match.toUpperCase();
    }).replace(/-/g, '').replace(/(^\w{1})/, s => s.toUpperCase());
}


module.exports = {
    generateIndex: gListIndexTemplate,
    generateColumn: gColumnTemplate,
    gAddEditTemplate: gAddEditTemplate,
    gServiceTemplate: gServiceTemplate,
    gDetailTemplate: gDetailTemplate
};                   